home *** CD-ROM | disk | FTP | other *** search
/ Best Tools for JAVA / Best Tools for JAVA.iso / CONVERTR / LWTOIV / LWTOIV / LWTOIV.C__ next >
Encoding:
Text File  |  1995-07-26  |  12.8 KB  |  407 lines

  1. ////////////////////////////////////////////////////////////
  2. // lwtoiv.c++
  3. //
  4. // A simplistic Lightwave to Open Inventor 3D object converter
  5. //
  6. // Written by Marvin Landis
  7. //            marvinl@amber.rc.arizona.edu
  8. //            May 1995
  9. //
  10. // This code is placed in the public domain.  It doesn't matter what
  11. // you do with it, but if you make any enhancements I would certainly
  12. // like to see them.
  13. //
  14. // There are several limitations and problems with this converter,
  15. // described in the Readme file which can be found in the original
  16. // distribution. If you don't have the original distribution,
  17. // e-mail me and I'll send it to you.
  18. //
  19. ////////////////////////////////////////////////////////////
  20.  
  21. #include <Inventor/SoDB.h>
  22. #include <Inventor/SbBasic.h>
  23. #include <Inventor/SbString.h>
  24. #include <Inventor/actions/SoSearchAction.h>
  25. #include <Inventor/actions/SoWriteAction.h>
  26. #include <Inventor/nodes/SoBaseColor.h>
  27. #include <Inventor/nodes/SoCoordinate3.h>
  28. #include <Inventor/nodes/SoIndexedFaceSet.h>
  29. #include <Inventor/nodes/SoIndexedLineSet.h>
  30. #include <Inventor/nodes/SoLabel.h>
  31. #include <Inventor/nodes/SoMaterial.h>
  32. #include <Inventor/nodes/SoNormal.h>
  33. #include <Inventor/nodes/SoNormalBinding.h>
  34. #include <Inventor/nodes/SoScale.h>
  35. #include <Inventor/nodes/SoSeparator.h>
  36. #include <Inventor/nodes/SoShapeHints.h>
  37. #include <Inventor/SoPath.h>
  38. #include <sys/types.h>
  39.  
  40. #define MAX_AMB        0.2;
  41.  
  42. static SbName           *snames;
  43.  
  44. static SoSeparator         *root;
  45. static SoScale          *scale;
  46. static SoCoordinate3       *coords;
  47. static SoShapeHints       *shapehints;
  48. static SoMaterial       *materials;
  49. static SoIndexedFaceSet       *faces;
  50. static SoIndexedLineSet    *lines;
  51.  
  52. static u_long        nSrfs = 0;
  53. static u_long        *fcnt, *lcnt;
  54.  
  55.  
  56. ////////////////////////////////////////////////////////////
  57. // Prints an error message to stderr and exits.
  58. ////////////////////////////////////////////////////////////
  59.  
  60. static void error(const char *message)
  61. {
  62.     fprintf(stderr, "Error: %s\n", message);
  63.     exit(1);
  64. }
  65.  
  66.  
  67. /////////////////////////////////////////////////////////////
  68. // Reads vertices into a SoCoordinate3 node.
  69. // Returns the number of vertices read.
  70. /////////////////////////////////////////////////////////////
  71.  
  72. static int read_pnts(u_long nbytes, FILE *file)
  73. {
  74.     float    (*pt)[3];
  75.     u_long    nPts;
  76.  
  77.     nPts = nbytes/sizeof(float[3]);
  78.  
  79.     coords = new SoCoordinate3;
  80.     pt = new float[nPts][3];
  81.  
  82.     fread((void *)pt, sizeof(float), nPts * 3, file);
  83.     coords->point.setValues(0, nPts, pt);
  84.  
  85.     delete pt;
  86.     return(nPts);
  87. }
  88.  
  89.  
  90. /////////////////////////////////////////////////////////////
  91. // Reads polygons into either a SoIndexedFaceSet or a SoIndexedLineSet node.
  92. // Returns the number of indexes (vertex and surface) read.
  93. /////////////////////////////////////////////////////////////
  94.  
  95. static int read_pols(u_long nbytes, FILE *file)
  96. {
  97.     short    *polys;
  98.     u_long    nPols;
  99.     SbBool    repeat;
  100.     int        i, j, k, cnt, snum, sc;
  101.  
  102.     // The Lightwave file specification states that the POLS chunk must be 
  103.     // preceded by the SRFS chunk.  If not, nSrfs will be 0.
  104.     if (nSrfs == 0)
  105.       error("No SRFS chunk in this Lightwave file");
  106.  
  107.     // Not really the number of polygons.  Actually the total number of
  108.     // shorts in this chunk.
  109.     nPols = nbytes/(sizeof(short));
  110.     polys = new short[nPols];
  111.     fread((void *)polys, sizeof(short), nPols, file);
  112.  
  113.     // Initialize the face and line counters.
  114.     fcnt = new u_long[nSrfs];
  115.     lcnt = new u_long[nSrfs];
  116.     for (i = 0; i < nSrfs; i++) fcnt[i] = lcnt[i] = 0;
  117.     faces = new SoIndexedFaceSet[nSrfs];
  118.     lines = new SoIndexedLineSet[nSrfs];
  119.  
  120.     i = 0;
  121.     while (i < nPols) {
  122.         cnt = polys[i++];
  123.  
  124.         // Surface index is found here.
  125.         sc = i + cnt;
  126.  
  127.         // Look for negative surface value (detail polygons follow).
  128.         if (polys[sc] < 0)
  129.           // Absolute value of the surface index.  Advance the pointer to
  130.           // skip over the short specifying how many detail polygons follow.
  131.           // (I don't think I should care, since detail polygons look like
  132.           // all other polygons as far as I'm concerned).
  133.           snum = -polys[sc++] - 1;
  134.         else
  135.           // Surface indexes are numbered starting at 1.
  136.           snum = polys[sc] - 1;
  137.  
  138.         // Look for repeated vertices in the polygon.  Actually test the
  139.         // coordinates, since I found some Lightwave objects in which the
  140.         // indexes were all different, but the coordinates still repeated.
  141.         repeat = FALSE;
  142.         for (j = i; j < i+cnt-1; j++)
  143.           for (k = j+1; k < i+cnt; k++)
  144.             if (coords->point[polys[j]] == coords->point[polys[k]])
  145.               repeat = TRUE;
  146.  
  147.         // If polygons have repeated vertices or have less than 3 vertices,
  148.         // add them to an SoIndexedLineSet for that surface. Otherwise add
  149.         // them to an SoIndexedFaceSet for that surface.
  150.         if ((repeat) || (cnt < 3)) {
  151.           for (j = 0; j < cnt; j++)
  152.             lines[snum].coordIndex.set1Value(lcnt[snum]++, (long) polys[i++]);
  153.           lines[snum].coordIndex.set1Value(lcnt[snum]++, SO_END_LINE_INDEX);
  154.     } else {
  155.           for (j = 0; j < cnt; j++)
  156.             faces[snum].coordIndex.set1Value(fcnt[snum]++, (long) polys[i++]);
  157.           faces[snum].coordIndex.set1Value(fcnt[snum]++, SO_END_FACE_INDEX);
  158.         }
  159.  
  160.         // Go on to the next polygon.
  161.         i = sc + 1;
  162.     }
  163.  
  164.     delete polys;
  165.  
  166.     return(nPols);
  167. }
  168.  
  169.  
  170. /////////////////////////////////////////////////////////////
  171. // Reads a SURF chunk, and sets all the appropriate values for a
  172. // SoShapeHints and SoMaterial node.  Returns the surface number.
  173. /////////////////////////////////////////////////////////////
  174.  
  175. static u_long    scnt=0;
  176. static int read_surf(u_long nbytes, FILE *file)
  177. {
  178.     u_long    ncnt = 0, bytesRead = 0;
  179.     u_long    type;
  180.     u_short    size;
  181.     char    ch, name[255];
  182.     int        i;
  183.     char    colr[4] = {200, 200, 200, 0};
  184.     float    fcolr[3];
  185.     float    fdiff = .4, fspec = 0, flumi = 0, fglos = 0, ftran = 0;
  186.     float    sman = 0;
  187.     u_short    diff = 100, spec = 0, glos = 0, lumi = 0, tran = 0;
  188.  
  189.     // Read the name of the surface.  Make sure the characters read are
  190.     // legal characters for a SbName type.
  191.     ch = fgetc(file);
  192.     bytesRead++;
  193.     if (snames[scnt].isIdentStartChar(ch)) name[ncnt++] = ch;
  194.     while (ch != 0) {
  195.       ch = fgetc(file);
  196.       bytesRead++;
  197.       if (snames[scnt].isIdentChar(ch)) name[ncnt++] = ch;
  198.     }
  199.     name[ncnt] = 0;
  200.  
  201.     // If the length of the surface name is odd, skip another byte.
  202.     if ((bytesRead % 2) > 0) {
  203.       ch = fgetc(file);
  204.       bytesRead++;
  205.     }
  206.  
  207.     while (bytesRead < nbytes) {
  208.  
  209.       // Handle the various sub-chunks.
  210.       fread(&type, sizeof(u_long), 1, file);
  211.       fread(&size, sizeof(u_short), 1, file);
  212.       switch (type) {
  213.  
  214.         case 'COLR':  fread(&colr, sizeof(char), 4, file);
  215.                       for (i = 0; i < 3; i++)
  216.                         fcolr[i] = (float) colr[i] / 255;
  217.                       break;
  218.  
  219.         case 'DIFF':  fread(&diff, sizeof(u_short), 1, file);
  220.                       fdiff = (float) diff / 255;
  221.                       break;
  222.  
  223.         case 'SPEC':  fread(&spec, sizeof(u_short), 1, file);
  224.                       fspec = (float) spec / 255;
  225.                       break;
  226.  
  227.         case 'GLOS':  fread(&glos, sizeof(u_short), 1, file);
  228.                       fglos = (float) spec / 1025;
  229.                       break;
  230.  
  231.         case 'LUMI':  fread(&lumi, sizeof(u_short), 1, file);
  232.                       flumi = (float) lumi / 255; 
  233.                       break;
  234.  
  235.         case 'TRAN':  fread(&tran, sizeof(u_short), 1, file);
  236.                       ftran = (float) tran / 255;
  237.                       break;
  238.  
  239.         case 'SMAN':  fread(&sman, sizeof(float), 1, file);
  240.                       break;
  241.  
  242.         default:      fseek(file, (long)size, SEEK_CUR);
  243.       }
  244.  
  245.       bytesRead += sizeof(u_long) + sizeof(u_short) + size;
  246.     }
  247.  
  248.     snames[scnt] = SbName(name);
  249.  
  250.     // Set the fields for this surface's SoShapeHints node.  Set the
  251.     // vertexOrdering to CLOCKWISE because of the negative scaling done
  252.     // around the z-axis  (see the main program).
  253.     shapehints[scnt].vertexOrdering = SoShapeHints::CLOCKWISE;
  254.     shapehints[scnt].faceType = SoShapeHints::UNKNOWN_FACE_TYPE;
  255.     shapehints[scnt].creaseAngle = sman;
  256.  
  257.     // Set the fields for this surface's SoMaterial node.
  258.     materials[scnt].diffuseColor.setValue(fdiff*fcolr[0], fdiff*fcolr[1], fdiff*fcolr[2]);
  259.     materials[scnt].specularColor.setValue(fspec*fcolr[0], fspec*fcolr[1], fspec*fcolr[2]);
  260.     materials[scnt].emissiveColor.setValue(flumi*fcolr[0], flumi*fcolr[1], flumi*fcolr[2]);
  261.     materials[scnt].shininess.setValue(fglos);
  262.     materials[scnt].transparency.setValue(ftran);
  263.     scnt++;
  264.  
  265.     return(scnt);
  266. }
  267.  
  268.  
  269. /////////////////////////////////////////////////////////////
  270. // Reads the SRFS chunk to determine how many surfaces are used by this
  271. // object.  Allocates memory for all the SoMaterial and SoShapeHints nodes,
  272. // and the table for all the SbNames.  Returns the number of surfaces.
  273. /////////////////////////////////////////////////////////////
  274.  
  275. static int read_srfs(u_long nbytes, FILE *file)
  276. {
  277.     char        *names;
  278.     int        i;
  279.  
  280.     names = new char[nbytes];
  281.     fread((void *)names, 1, nbytes, file);
  282.  
  283.     i = 0;
  284.     while (i < nbytes) {
  285.       i += strlen(&names[i]);
  286.       nSrfs++;
  287.       // Skip any extra nulls at the end of the surface name.
  288.       while ((names[i] == '\0') && (i < nbytes)) i++;
  289.     }
  290.  
  291.     shapehints = new SoShapeHints[nSrfs];
  292.     materials = new SoMaterial[nSrfs];
  293.     snames = new SbName[nSrfs];
  294.  
  295.     delete names;
  296.     return(nSrfs);
  297. }
  298.  
  299.  
  300. /////////////////////////////////////////////////////////////
  301. // Main program.
  302. /////////////////////////////////////////////////////////////
  303.  
  304. main(int argc, char *argv[]) {
  305.     SoSeparator    *sep1, *sep2;
  306.     SoLabel    *lab;
  307.     FILE    *file;
  308.     u_long    datasize, bytesread;
  309.     u_long    type, size;
  310.     int        i;
  311.  
  312.     if (argc != 2)
  313.        error("Usage: lwtoiv file.lwob [> file.iv]");
  314.     file = fopen(argv[1], "r");
  315.  
  316.     // Initialize the Inventor database.
  317.     SoDB::init();
  318.  
  319.     // Make sure the Lightwave file is an IFF file.
  320.     fread(&type, sizeof(u_long), 1, file);
  321.     if (type != 'FORM')
  322.       error("Not an IFF file (Missing FORM tag)");
  323.  
  324.     fread(&datasize, sizeof(u_long), 1, file);
  325.  
  326.     // Make sure the IFF file has a LWOB form type.
  327.     fread(&type, sizeof(u_long), 1, file);
  328.     if (type != 'LWOB')
  329.       error("Not a lightwave object (Missing LWOB tag)");
  330.  
  331.     // The root node.
  332.     root = new SoSeparator;
  333.     root->ref();
  334.  
  335.     // Read all Lightwave chunks.
  336.     bytesread = 4;
  337.     while (bytesread < datasize) {
  338.  
  339.       fread(&type, sizeof(u_long), 1, file);
  340.       fread(&size, sizeof(u_long), 1, file);
  341.  
  342.       switch (type) {
  343.         case 'PNTS':    read_pnts(size, file); break;
  344.         case 'POLS':    read_pols(size, file); break;
  345.         case 'SRFS':    read_srfs(size, file); break;
  346.         case 'SURF':    read_surf(size, file); break;
  347.         default:    fseek(file, (long)size, SEEK_CUR);
  348.       }
  349.  
  350.       bytesread += size + 8;
  351.  
  352.     }
  353.  
  354.     // Inventor's z-axis points in the opposite direction from Lightwave. 
  355.     scale = new SoScale;
  356.     scale->scaleFactor.setValue(1, 1, -1);
  357.  
  358.     // Add the SoScale and SoCoordinate3 node to the root hierarchy.
  359.     root->addChild(scale);
  360.     root->addChild(coords);
  361.  
  362.     for (i = 0; i < nSrfs; i++) {
  363.  
  364.       // Will always be added as a child to the root node. Will contain
  365.       // a SoLabel node and another SoSeparator node as children.
  366.       sep1 = new SoSeparator;
  367.  
  368.       // Will always be added as a child to the sep1 node. Will contain
  369.       // SoShapeHints, SoMaterial, SoIndexedFaceSet, and SoIndexedLineSet
  370.       // nodes as children.
  371.       sep2 = new SoSeparator;
  372.  
  373.       // Add the SoShapeHints, SoMaterial, SoIndexedFaceSet, and
  374.       // SoIndexedLineSet nodes as children to sep2.
  375.       sep2->addChild(&shapehints[i]);
  376.       sep2->addChild(&materials[i]);
  377.       // If there are faces for this surface.
  378.       if (fcnt[i] > 0)
  379.         sep2->addChild(&faces[i]);
  380.       // If there are lines for this surface.
  381.       if (lcnt[i] > 0) {
  382.         sep2->addChild(&lines[i]);
  383.         fprintf(stderr,"WARNING: added polyline(s) to \"%s\" node\n",
  384.                 snames[i].getString());
  385.       }
  386.  
  387.       // Add the SoLabel and SoSeperator nodes as children to sep1.
  388.       lab = new SoLabel;
  389.       lab->label.setValue(snames[i]);
  390.       sep1->addChild(lab);
  391.       sep1->addChild(sep2);
  392.  
  393.       // Add this surface's SoSeperator node as a child to root.
  394.       root->addChild(sep1);
  395.       sep1->setName(snames[i]);
  396.     }
  397.  
  398.     // Write the entire root hierarchy to stdout.
  399.     SoWriteAction wa;
  400.     wa.apply(root);
  401.  
  402.     fprintf(stderr, "lw->iv conversion done.\n");
  403.  
  404.     return 0;
  405. }
  406.  
  407.